home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Palettes / PAStringList / PAFilenameList.m < prev    next >
Text File  |  1995-06-12  |  15KB  |  355 lines

  1. #import "PAFilenameList.h"
  2. #import <sys/dir.h>
  3. #import <apps/InterfaceBuilder.h>
  4.  
  5. /******************************************************************************
  6. PAFilenameList
  7.  
  8.     The PAFilenameList (a subclass of PAStringList) is a convenient way to deal with lists of filenames. It contains methods for generating lists of filenames from given directories. There is also a specific method for searching the standard libraries (/NextLibrary, /LocalLibrary, ~/Libary). Files can be limited to particular extensions and can be returned with or without their full path and extension.
  9.     
  10.     To use this object inside of InterfaceBuilder, simply drag its icon from the palettes window into the suitcases window. Then drag in a browser and set its delegate to be the filenameList. Then enter something like "Fonts" in the libraries textfield or "/NextLibrary/Documentation" in the directories textfield, type in an extension if you like(font, slo, rtf, etc...) and test interface.
  11.     
  12.     Copyright 1992, Jeff Martin (jmartin@next.com) (415) 780-3833.
  13. ******************************************************************************/
  14.  
  15. #define FILE_FROM_PATH(a)( (a)? rindex(a,'/')? rindex(a,'/')+1 : (a) : 0L )
  16. #define EXT_FROM_PATH(a) ( (a)? rindex(a,'.')? rindex(a,'.')+1 : 0L : 0L)
  17. #define EXT_STRIP(a)     ( (a)? rindex(a,'.')? *rindex(a,'.') = '\0' : 0L :0L)
  18.  
  19. @implementation PAFilenameList : PAStringList
  20.  
  21.  
  22. /******************************************************************************
  23.     addFilename:(char *)filename stripPath:(BOOL)stripPath 
  24.         stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent noCopy:(BOOL)noCopy 
  25.         sorted:(BOOL)sorted at:(int)at
  26.  
  27.     This method adds the given filename to the list of strings giving the option to strip the path and/or the extension. It simply does the requested strips and calls addString:ifAbsent:noCopy:sorted:at:(PAStringList). Returns the value of that method (self).
  28. ******************************************************************************/
  29. - addFilename:(const char *)filename stripPath:(BOOL)stripPath stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent noCopy:(BOOL)noCopy sorted:(BOOL)sorted at:(int)at
  30. {
  31.     char newFilename[MAXPATHLEN+1];
  32.     
  33.     // Get filename with appropriate stripping
  34.     sprintf(newFilename, "%s", stripPath? FILE_FROM_PATH(filename) : filename);
  35.     if(stripExt) EXT_STRIP(newFilename);
  36.     
  37.     // If string was sent no copy, then free it (we have our own)
  38.     if(noCopy) free((char *)filename);
  39.     
  40.     // Add new string with noCopy 
  41.     return [self addString:newFilename ifAbsent:ifAbsent noCopy:NO 
  42.         sorted:sorted at:at];
  43. }
  44.  
  45. /******************************************************************************
  46.     addFilenames:(char **)filenames stripPath:(BOOL)stripPath ...
  47.     addPAFilenameList:filenameList stripPath:(BOOL)stripPath...
  48.  
  49.     These methods allow for lists of strings to be added as filenames (with or without their full paths and extensions).
  50.     addFilename: adds filenames from a NULL terminated array of char pointers. Returns self.
  51.     addPAFilenameList: add filenames from a PAFilenameList. Returns self.
  52. ******************************************************************************/
  53. - addFilenames:(const char *const*)filenames stripPath:(BOOL)stripPath stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent noCopy:(BOOL)noCopy sorted:(BOOL)sorted at:(int)at
  54. {
  55.     char *const*temp = filenames;
  56.     
  57.     // Add each string individually, incrementing 'at' to preserve their order
  58.     if(temp) while(*temp) {
  59.         [self addFilename:*temp stripPath:stripPath stripExt:stripExt 
  60.             ifAbsent:ifAbsent noCopy:noCopy sorted:sorted at:at];
  61.             at++; temp++;
  62.     }
  63.     
  64.     // If 'noCopy' then we own the memory 'filenames' and should free it
  65.     if(noCopy) free((char **)filenames);
  66.     return self;
  67. }
  68.  
  69. - addPAFilenameList:filenameList stripPath:(BOOL)stripPath stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent noCopy:(BOOL)noCopy sorted:(BOOL)sorted at:(int)at
  70. {
  71.     int i;
  72.     
  73.     for(i=0; i<[filenameList count]; i++)
  74.         [self addFilename:[filenameList stringAt:i] stripPath:stripPath 
  75.         stripExt:stripExt ifAbsent:ifAbsent noCopy:noCopy sorted:sorted 
  76.         at:at++];
  77.     return self;
  78. }
  79.  
  80. /******************************************************************************
  81.     addFilenamesFromDirectories:withExts:
  82.  
  83.     addFilenamesFromDirectories looks out in the directories specified for files with the given extensions (NULL for all files) and adds them to the list. 'directory' is a delimited list of directories and 'ext' is a delimited list of extensions. Assumed delimiters are space, tab, newline, return, colon and comma (' ', '\t', '\n', '\r', ':', ',', '\0'). Returns self.
  84.     addFilenamesFromStandardLibrariesDirectory goes a step farther and looks in /NextLibary, /LocalLibrary and ~/Libary for the given directories. This is a convenience for the cases where an app searches the standard libraries. Returns self.
  85. ******************************************************************************/
  86. - addFilenamesFromDirectories:(const char *)dirs withExts:(const char *)exts stripPath:(BOOL)stripPath stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent sorted:(BOOL)sorted at:(int)at
  87. {
  88.     char dirDels[] = { ' ', '\t', '\n', '\r', ':', ',', '\0' };
  89.     char extDels[] = { ' ', '\t', '\n', '\r', ':', ',', '.', '\0' };
  90.     id dirList = [[[PAStringList alloc] init] addDelimitedStrings:dirs
  91.         delimiters:dirDels];
  92.     id extList = [[[PAStringList alloc] init] addDelimitedStrings:exts
  93.         delimiters:extDels];
  94.     DIR    *thedir;
  95.     char tempName[MAXPATHLEN+1];
  96.     struct direct *entry;
  97.     int i;
  98.     
  99.     // Look at each directory
  100.     for(i=0; i<[dirList count]; i++) {
  101.         char directory[MAXPATHLEN];
  102.         
  103.         // Expand and Open the current directory
  104.         sprintf(directory, "%s", [dirList stringAt:i]);
  105.         PAExpandFilename(directory);
  106.         thedir = opendir(directory);
  107.  
  108.         // Look at each entry in the dir. If they aren't hidden(start with '.') 
  109.         //   and there was no given extension or the extension matches one in 
  110.         //     the extensionList, add filename.
  111.         while(thedir && (entry=readdir(thedir)))
  112.             if((*entry->d_name != '.') && (!exts || 
  113.                 [extList stringExists:EXT_FROM_PATH(entry->d_name)])) {
  114.                 sprintf(tempName,"%s/%s", directory, entry->d_name);
  115.                 [self addFilename:tempName stripPath:stripPath 
  116.                     stripExt:stripExt ifAbsent:ifAbsent noCopy:NO sorted:sorted 
  117.                         at:at++];
  118.             }
  119.     
  120.         // Close the directory, store the file counter and return the files.
  121.         if(thedir) closedir(thedir);
  122.     }
  123.  
  124.     [dirList freeStrings]; [dirList free];
  125.     [extList freeStrings]; [extList free];
  126.     return self;
  127. }
  128.  
  129. - addFilenamesFromStandardLibrariesDirectories:(const char *)dirs
  130.     withExts:(const char *)exts stripPath:(BOOL)stripPath 
  131.     stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent sorted:(BOOL)sorted 
  132.     at:(int)at
  133. {
  134.     char dirDels[] = { ' ', '\t', '\n', '\r', ':', ',', '\0' };
  135.     id dirList = [[[PAStringList alloc] init] addDelimitedStrings:dirs
  136.         delimiters:dirDels];
  137.     char temp[3*MAXPATHLEN];
  138.     int i, oldCount = [self count];
  139.     
  140.     // For each given directory
  141.     for(i=0; i<[dirList count]; i++) {
  142.         const char *dir = [dirList stringAt:i];
  143.  
  144.         // Add files from NextLibrary
  145.         sprintf(temp, "/NextLibrary/%s:/LocalLibrary/%s:%s/Library/%s",
  146.             dir, dir, NXHomeDirectory(), dir);
  147.         [self addFilenamesFromDirectories:temp withExts:exts 
  148.             stripPath:stripPath stripExt:stripExt ifAbsent:ifAbsent 
  149.             sorted:sorted at:at];
  150.         
  151.         // Increment 'at' value
  152.         at += [self count] - oldCount; oldCount = [self count];
  153.     }
  154.     [dirList freeStrings]; [dirList free];
  155.     return self;
  156. }
  157.  
  158.  
  159. /******************************************************************************
  160.     addDelimitedFilenames:delimiters:stripPath:stripExt:ifAbsent:sorted:at:at
  161.  
  162.     This method is just like addDelimitedStrings: but it allows the filnames to be stripped of their paths and/or extensions before being added. Returns self.
  163. ******************************************************************************/
  164. - addDelimitedFilenames:(const char *)filenames delimiters:(const char *)dels stripPath:(BOOL)stripPath stripExt:(BOOL)stripExt ifAbsent:(BOOL)ifAbsent sorted:(BOOL)sorted at:(int)at
  165. {
  166.     id filenameList = [[[PAStringList alloc] init] 
  167.         addDelimitedStrings:filenames delimiters:dels];
  168.  
  169.     [self addPAFilenameList:filenameList stripPath:stripPath stripExt:stripExt
  170.         ifAbsent:ifAbsent noCopy:YES sorted:sorted at:at];
  171.     [filenameList free];
  172.     return self;
  173. }
  174.  
  175. /******************************************************************************
  176.     sortFilenameIgnoringPath:
  177.     filenameCmp()
  178.  
  179.     sortFilenamesIgnoringPath: is just like sortStrings except that the full paths are stripped from the file before it is compared. This is useful for cases where you want the files to be in alphabetical order regardless of their full path, while preserving the full path. Returns self.
  180. ******************************************************************************/
  181. - sortFilenamesIgnoringPath:sender
  182. {
  183.     qsort(dataPtr, [self count], sizeof(char *), filenameCmp);
  184.     isSorted = YES;
  185.     return self;
  186. }
  187.  
  188. // Wrap around strcasecmp to cmp filenames regardless of their path(strip path)
  189. int filenameCmp(const void *s1, const void *s2)
  190. {
  191.     char *fn1 = FILE_FROM_PATH(*(char **)s1);
  192.     char *fn2 = FILE_FROM_PATH(*(char **)s2);
  193.     if(fn1 == fn2) return 0;
  194.     else if(!fn1) return 1; else if(!fn2) return -1;
  195.     else return strcasecmp(fn1, fn2);
  196. }
  197.  
  198. // Archiving methods
  199. - write:(NXTypedStream *)stream
  200. {    
  201.     [super write:stream];
  202.  
  203.     NXWriteTypes(stream, "***cccccc",
  204.         &plLibs, &plDirs, &plExts,
  205.         &plFromAppDir, &plFromBundleDir,
  206.         &plStripPath, &plStripExt,
  207.         &plIfAbsent, &plSorted);
  208.     return self;
  209. }
  210.  
  211. - read:(NXTypedStream *)stream
  212. {
  213.     [super read:stream];
  214.  
  215.     NXReadTypes(stream, "***cccccc",
  216.         &plLibs, &plDirs, &plExts,
  217.         &plFromAppDir, &plFromBundleDir,
  218.         &plStripPath, &plStripExt,
  219.         &plIfAbsent, &plSorted);
  220.     return self;
  221. }
  222.  
  223. // Does the work of preloading after object is read in
  224. - awake
  225. {
  226.     [super awake];
  227.  
  228.     // Don't preload if editing in IB and not testing interface.
  229.     //   'isTestingInterface' is currently bogus durring unarchival(bug #35351)
  230.     //   so I test to see if mainMenu is visible, which it isn't while test
  231.     //   interface mode is being set up. Hopefully 'isTestingInterface' will
  232.     //   work in the future. I think this hack works fine for now.
  233.     //if(!strcmp([NXApp appName], "InterfaceBuilder"))
  234.     if([NXApp conformsTo:@protocol(IB)])
  235.         if([[NXApp mainMenu] isVisible])
  236.             return self;
  237.     
  238.     // Add filenames from given libraries
  239.     [self addFilenamesFromStandardLibrariesDirectories:plLibs withExts:plExts 
  240.         stripPath:plStripPath stripExt:plStripExt ifAbsent:plIfAbsent 
  241.         sorted:plSorted at:[self count]];
  242.     
  243.     // Add filenames from given directies
  244.     [self addFilenamesFromDirectories:plDirs withExts:plExts 
  245.         stripPath:plStripPath stripExt:plStripExt ifAbsent:plIfAbsent 
  246.         sorted:plSorted at:[self count]];
  247.  
  248.     // Add filenames from app wrapper if requested
  249.     if(plFromAppDir)
  250.         [self addFilenamesFromDirectories:[[NXBundle mainBundle] directory]
  251.         withExts:plExts stripPath:plStripPath stripExt:plStripExt 
  252.         ifAbsent:plIfAbsent sorted:plSorted at:[self count]];
  253.  
  254.     // Add filenames from bundle dir if requested
  255.     if(plFromBundleDir) [self addFilenamesFromDirectories:
  256.         [[NXBundle bundleForClass:[self class]] directory] withExts:plExts 
  257.         stripPath:plStripPath stripExt:plStripExt ifAbsent:plIfAbsent 
  258.         sorted:plSorted at:[self count]];
  259.  
  260.     // Reset all preload values
  261.     [self setPreLoadLibraries:NULL]; [self setPreLoadDirectories:NULL];
  262.     [self setPreLoadExtensions:NULL];
  263.     [self setPreLoadFromAppDir:NO]; [self setPreLoadFromBundleDir:NO];
  264.     [self setPreLoadStripPath:NO]; [self setPreLoadStripExt:NO];
  265.     [self setPreLoadIfAbsent:NO]; [self setPreLoadSorted:NO];
  266.     return self;
  267. }
  268.  
  269. /******************************************************************************
  270.     (const char *)preLoadLibraries, setPreLoadLibraries:(const char *)libs
  271.     (const char *)preLoadDirectories, setPreLoadDirectories:(const char *)dirs
  272.     (const char *)preLoadExtensions, setPreLoadExtensions:(const char *)exts
  273.     (BOOL)preLoadFromAppDir, setPreLoadFromAppDir:(BOOL)flag
  274.     (BOOL)preLoadFromBundleDir, setPreLoadFromBundleDir:(BOOL)flag
  275.     (BOOL)preLoadStripPath, setPreLoadStripPath:(BOOL)flag
  276.     (BOOL)preLoadStripExt, setPreLoadStripExt:(BOOL)flag
  277.     (BOOL)preLoadIfAbsent, setPreLoadIfAbsent:(BOOL)flag
  278.     (BOOL)preLoadSorted, setPreLoadSorted:(BOOL)flag
  279.     
  280.     These methods query and set search paths, extensions and flags to preload the string list when unarchived. This allows for an InterfaceBuilder palette to set the StringList to load interesting things when unarchived (ie, "get all of the files of type 'font' from the standard library directory 'Fonts' ").
  281. ******************************************************************************/
  282. // Return and set the Libraries for preload
  283. - (const char *)preLoadLibraries { return plLibs; }
  284. - setPreLoadLibraries:(const char *)libs
  285.     free(plLibs); 
  286.     plLibs = (libs && strlen(libs))? 
  287.         NXCopyStringBufferFromZone(libs, [self zone]) : NULL;
  288.     return self;
  289. }
  290.  
  291. // Return and set the Directories for preload
  292. - (const char *)preLoadDirectories { return plDirs; }
  293. - setPreLoadDirectories:(const char *)dirs
  294.     free(plDirs); 
  295.     plDirs = (dirs && strlen(dirs))? 
  296.         NXCopyStringBufferFromZone(dirs, [self zone]) : NULL;
  297.     return self;
  298. }
  299.  
  300. // Return and set the Extensions for preload
  301. - (const char *)preLoadExtensions { return plExts; }
  302. - setPreLoadExtensions:(const char *)exts
  303.     free(plExts); 
  304.     plExts = (exts && strlen(exts))?
  305.         NXCopyStringBufferFromZone(exts, [self zone]) : NULL;
  306.     return self;
  307. }
  308.  
  309. // Return and set whether or not to load from application dir
  310. - (BOOL)preLoadFromAppDir 
  311. { return plFromAppDir; }
  312. - setPreLoadFromAppDir:(BOOL)flag { plFromAppDir = flag; return self; }
  313.  
  314. // Return and set whether or not to load from bundle dir
  315. - (BOOL)preLoadFromBundleDir { return plFromBundleDir; }
  316. - setPreLoadFromBundleDir:(BOOL)flag { plFromBundleDir = flag; return self; }
  317.  
  318. // Return and set whether or not to strip paths from preloaded files
  319. - (BOOL)preLoadStripPath { return plStripPath;}
  320. - setPreLoadStripPath:(BOOL)flag { plStripPath = flag; return self; }
  321.  
  322. // Return and set whether or not to strip extensions from preloaded files
  323. - (BOOL)preLoadStripExt { return plStripExt; }
  324. - setPreLoadStripExt:(BOOL)flag { plStripExt = flag; return self; }
  325.  
  326. // Return and set whether or not to 'add preloaded files only if absent'
  327. - (BOOL)preLoadIfAbsent { return plIfAbsent; }
  328. - setPreLoadIfAbsent:(BOOL)flag { plIfAbsent = flag; return self; }
  329.  
  330. // Return and set whether or not to sort preloaded files
  331. - (BOOL)preLoadSorted { return plSorted; }
  332. - setPreLoadSorted:(BOOL)flag { plSorted = flag; return self; }
  333.  
  334. // Interface Builder support
  335. - (const char *)getInspectorClassName { return "PAFilenameListInspector"; }
  336.  
  337. @end
  338.  
  339. char *PAExpandFilename(char *fn)
  340. {
  341.     char oldFilename[MAXPATHLEN], *fn2 = fn+1;
  342.     if(*fn=='~') {
  343.         if(fn[1]=='/') fn2++;
  344.         strcpy(oldFilename, fn2);
  345.         sprintf(fn, "%s/%s", NXHomeDirectory(), oldFilename);
  346.     }
  347.     return fn;
  348. }
  349.  
  350.  
  351.  
  352.